#ifndef VRPTW_HPP_
#	define VRPTW_HPP_

#	include "Client.hpp"
#	include "exc.hpp"
#   include "Depot.hpp"

#	include <cassert>
#   include <cmath>

#   define TRONC_ACTIVATED

struct ServiceInfo;
class Vehicle;

class VRPTW
{
	public:
		typedef enum { REALIZABLE_LTE = 0, REALIZABLE_GTE, REALIZABLE_NONE } RealizableStatus;
        
        static double tronc(double inValue)
        {
#   ifdef TRONC_ACTIVATED
            int didi;
            didi = (int)floor(inValue * 100.0);
            return ((double)didi * 0.01);
#   endif
            return (inValue);
        }
        
		VRPTW(const std::string&	inFilename)	EXC_THROWER();
		~VRPTW();
		
		void		print() const;
		Client&		operator[](unsigned inId) EXC_THROWER()
		{
			if (vrNClients == 0)
				EXC_THROW("unable to access : vrptw is empty");
			
			return (*vrClients[inId]);
		}
		
		const Client&		operator[](unsigned inId) const EXC_THROWER()
		{
			if (vrNClients == 0)
				EXC_THROW("unable to access : vrptw is empty");
			
			return (*vrClients[inId]);
		}
		
		unsigned			getVehicleCapacity() const
		{	return (vrVehicleCapacity);		}
		
        const Depot&        getDepot() const
        {   return (*vrDepot);       }
        
        double              getDistanceBetween(unsigned inClient1, unsigned inClient2) const
        {
			if (inClient1 == (vrNClients + 1))
				inClient1 = vrNClients;
				
			if (inClient2 == (vrNClients + 1))
				inClient2 = vrNClients;
				
			if (isRDepot(inClient1))
				inClient1 = vrNClients;
				
			if (isRDepot(inClient2))
				inClient2 = vrNClients;
			
            if (inClient1 == DEPOT)
                inClient1 = vrNClients;
            
            if (inClient2 == DEPOT)
                inClient2 = vrNClients;
            
            if (inClient1 > vrNClients)
                EXC_THROW("inClient1 given is wrong");
                
            if (inClient2 > vrNClients)
                EXC_THROW("inClient2 given is wrong");
            
            return (vrDistances[inClient1 * (vrNClients + 1) + inClient2]);
        }
        
        unsigned            size() const
        {   return (vrNClients);    }
        
        const std::multimap<double, unsigned>&  getDistanceByClient(unsigned inClient) const
        {
            if (inClient == DEPOT)
                inClient = vrNClients;
                
            return vrDistancesByClient[inClient];
        }
        
        unsigned	buildNewRDepot()
        {
			assert(vrNextRDepot != 0xFFFFFFFF);
			
			vrNextRDepot++;
			
			return (vrNextRDepot - 1);
		}
		
		bool		isRDepot(unsigned inValue) const
		{
			return ((inValue != DEPOT) && (inValue >= vrNClients));
		}
		
		void		printDotPoint(FILE* inFile, unsigned inClient) const;
        
        
		VRPTW::RealizableStatus		checkInsert(const ServiceInfo&	inI,
												const ServiceInfo&	inJ,
												unsigned			inN) const;

        VRPTW::RealizableStatus     checkInsert2( const ServiceInfo&  inI,
                                                  const ServiceInfo&  inJ,
                                                  unsigned            inN,
                                                  unsigned            inCCapacity) const;
                                                  
        VRPTW::RealizableStatus     checkInsert3( const ServiceInfo&  inI,
                                                  const ServiceInfo&  inJ,
                                                  unsigned            inN,
                                                  unsigned            inCCapacity) const;
                                                  
        VRPTW::RealizableStatus		checkInsert4( 	const Vehicle& 	inV,
													unsigned		inI,
													unsigned		inJ,
													unsigned		inN,
													unsigned		inCCapacity) const;
	protected:
		const std::string&	vrFilename;
		unsigned			vrNClients;
		unsigned			vrVehicleCapacity;
		unsigned			vrNextRDepot;
		Client**			vrClients;
        Depot*              vrDepot;
        
        std::multimap<double, unsigned>*    vrDistancesByClient;

        double*                         vrDistances;
        double*                         vrGains;
};

#endif
